package com.quectel.emp.util;

import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.RandomUtil;
import com.quectel.business.common.sms.SmsBusiness;
import com.quectel.constant.global.SMSConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.emp.constants.EmpSystemConstants;
import com.quectel.emp.interceptor.LoginEmpSession;
import com.quectel.sys.module.sys.service.MsgService;
import com.quectel.util.common.JacksonUtils;
import com.quectel.util.redis.RedisUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 验证码发送
 *
 * @author caolu
 * @email louis.cao@quectel.com
 */
@Component
public class SmsComponent {

    /**
     * 短信发送的前缀  key：prefix+mobile value:code
     */
    private static final String SMS_MSG = "SMS_MSG";

    /**
     * 短信发送限制根据手机号
     */
    private static final String SMS_MSG_LIMIT_LOCK_BY_MOBILE = "SMS_MSG_LIMIT_LOCK_BY_MOBILE:";

    /**
     * 短信发送限制根据session
     */
    private static final String SMS_MSG_LIMIT_LOCK_BY_SESSION = "SMS_MSG_LIMIT_LOCK_BY_SESSION:";

    /**
     * 发送短信的时间间隔 默认60s
     */
    private static final int SMS_MSG_TIME_LIMIT = 50;
    /**
     * 验证码有效期
     */
    private static final int DEFAULT_CODE_EXPIRED_SECONDS = 5 * 60;

    @DubboReference
    private MsgService smsService;

    @Autowired
    private SmsBusiness smsBusiness;

    /**
     * 发送验证码
     *
     * @param tenantId    租户id可能为空
     * @param mobile
     * @param verCodeType
     * @return 验证码
     */
    public String sendVerCode(Long tenantId, String mobile, SMSConstants.VerCodeType verCodeType) {
        if (!PhoneUtil.isMobile(mobile)) {
            return null;
        }
        if (!RedisUtils.setnx(SMS_MSG_LIMIT_LOCK_BY_MOBILE + mobile, SystemConstants.YES.toString(), SMS_MSG_TIME_LIMIT, TimeUnit.SECONDS)) {
            //发送过于频繁
            return null;
        }

        if (SessionHolder.getLoginEmpSession() != null) {
            // 根据session限制频率
            if (!RedisUtils.setnx(SMS_MSG_LIMIT_LOCK_BY_SESSION + SessionHolder.getLoginEmpSession().getOpenId(), SystemConstants.YES.toString(), SMS_MSG_TIME_LIMIT, TimeUnit.SECONDS)) {
                return null;
            }
        }

        String code = null;
        int expireDuration = DEFAULT_CODE_EXPIRED_SECONDS;
        //发送验证码
        if (SMSConstants.VerCodeType.EMP_OFFICIAL_ACCOUNTS_BINDING.equals(verCodeType)) {
            code = RandomUtil.randomNumbers(4);
        } else if (SMSConstants.VerCodeType.EMP_EDIT_MOBILE.equals(verCodeType)) {
            code = RandomUtil.randomNumbers(4);
        } else if (SMSConstants.VerCodeType.EMP_EDIT_PASS.equals(verCodeType)) {
            code = RandomUtil.randomNumbers(4);
        } else if (SMSConstants.VerCodeType.EMP_APP_VER_CODE_LOGIN.equals(verCodeType)) {
            code = RandomUtil.randomNumbers(4);
        }

        smsBusiness.sendVerCode(tenantId, mobile, code, verCodeType);


        RedisUtils.set(SMS_MSG + verCodeType.toString() + mobile, code,
                expireDuration, TimeUnit.SECONDS);

        return code;
    }

    public boolean checkVerCode(String mobile, String recCode, SMSConstants.VerCodeType verCodeType) {
        String sendCode = RedisUtils.get(SMS_MSG + verCodeType.toString() + mobile);
        if (StringUtils.isNotBlank(sendCode) && Objects.equals(sendCode, recCode)) {
            return true;
        }
        return false;
    }

    /**
     * 删除验证码
     *
     * @param mobile
     * @param verCodeType
     * @return
     */
    public void invalidVerCode(String mobile, SMSConstants.VerCodeType verCodeType) {
        RedisUtils.del(SMS_MSG + verCodeType.toString() + mobile);
    }

    /**
     * 得到session
     *
     * @return
     */
    private LoginEmpSession getLoginMobileUserSession(HttpServletRequest httpServletRequest) {
        String token = httpServletRequest.getHeader("token");
        if (org.apache.commons.lang3.StringUtils.isEmpty(token)) {
            token = httpServletRequest.getParameter("token");
        }
        if (StringUtils.isNotBlank(token)) {
            //header和url都没有传入token
            LoginEmpSession session = (LoginEmpSession) httpServletRequest.getAttribute(EmpSystemConstants.TOKEN_EMP_SESSION);
            if (session != null) {
                return session;
            }
            String sessionStr = RedisUtils.get(EmpSystemConstants.TOKEN_EMP_SESSION + token);
            if (StringUtils.isNotBlank(sessionStr)) {
                return JacksonUtils.parse(sessionStr, LoginEmpSession.class);
            }
        }
        return null;
    }

}
